/*
 * Copyright © 2011 SenseForce.com.
 * The Software shall be used for Good, not Evil.
 */

package com.senseforce.classes;

import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;
import javax.microedition.midlet.*;
import java.util.*;

/**
 *
 * @author jcccn
 * @site http://www.senseforce.com/
 */
public class JigsawPuzzleCanvas extends Canvas implements CommandListener {
	
	private static final String imgPath = "/jigsawPuzzle.png";
	
	private Command exitCommand = new Command("Exit", Command.EXIT, 0);
	private Command continueCommand = new Command("Continue", Command.SCREEN, 0);
	
	private MIDlet midlet;
	private Graphics graphics = null;
	private Image image = null;
	private int edge = 0;	//边长
	private int[][] map = { {00, 01, 02, 03},
							{10, 11, 12, 13},
							{20, 21, 22, 23},
							{30, 31, 33, 32} };
	private boolean willShowFullImage = false;
	private int willSwapX = 0;	//-1,0,1
	private int willSwapY = 0;
	private int xmap33 = 3;
	private int ymap33 = 3;
	
	public JigsawPuzzleCanvas(MIDlet midlet) {
		this.midlet = midlet;
		try {
			image = Image.createImage(imgPath);
			edge = image.getWidth()/4;
		} catch(Exception ex) {
			System.out.println("exception when create the image with path " + imgPath);
		}
		setCommandListener(this);
		addCommand(exitCommand);
		initMap();
	}
	
	private void initMap() {
		Random random = new Random();
		int temp, x1, x2, y1, y2;
		for(int repeatCount = 100; repeatCount > 0; repeatCount --) {
			x1 = random.nextInt(4);
			x2 = random.nextInt(4);
			y1 = random.nextInt(4);
			y2 = random.nextInt(4);
			temp = map[x1][y1];
			map[x1][y1] = map[x2][y2];
			map[x2][y2] = temp;
		}
		repaint();
	}
	
	private boolean isSuccess() {
		for (int x = 0; x < 4; x ++) {
			for (int y = 0; y < 4; y++) {
				int xOnImage = map[x][y] / 10;
				int yOnImage = map[x][y] % 10;
				if ((xOnImage != x) || (yOnImage != y)) {
					return false;
				}
			}
		}
		return true;
	}
	
	private void swap(int xOf33, int yOf33, int xOfTarget, int yOfTarget) {
		map[xOf33][yOf33] = map[xOfTarget][yOfTarget];
		map[xOfTarget][yOfTarget] = 33;
	}
	
	public void paint(Graphics g) {
		graphics = g;
		g.setColor(255, 255, 255);
		g.fillRect(0, 0, getWidth(), getHeight());
		//g.setColor(0, 0, 255);
		//g.drawRect(-1, -1, image.getWidth()-2, image.getHeight()-2);
		int xOnImage = 0;
		int yOnImage = 0;
		for (int x = 0; x < 4; x++) {
			for (int y = 0; y < 4; y++) {
				if (map[x][y] != 33) {
					xOnImage = map[x][y] / 10;
					yOnImage = map[x][y] % 10;
					g.drawRegion(image, xOnImage*edge, yOnImage*edge, edge, edge, Sprite.TRANS_NONE, x*edge, y*edge, Graphics.LEFT | Graphics.TOP);
					//System.out.println("x,y,xOnImage,yOnImage,edge:"+x+", "+y+", "+xOnImage+", "+yOnImage+", "+edge);
				}
				else {
					//g.setColor(150, 40, 255);
					g.setColor(255, 0, 0);
					g.fillRect(x*edge+2, y*edge+2, edge-4, edge-4);
					
				}
				g.setColor(0, 255, 0);
				g.drawRect(x*edge, y*edge, edge, edge);
			}
		}
		
		if(willSwapX+willSwapY != 0) {
			g.setColor(255, 0, 0);
			g.drawRect((xmap33+willSwapX)*edge+2, (ymap33+willSwapY)*edge+2, edge-4, edge-4);
		}
		
		if (willShowFullImage) {
			g.drawImage(image, 0, 0, Graphics.TOP | Graphics.LEFT);
			g.setColor(255, 0, 0);
			g.fillRect(image.getWidth()-edge, image.getHeight()-edge, edge, edge);
		}
		
		if (isSuccess()) {
			g.setColor(0, 0, 0);
			g.drawString("Congratulations! Once again?", getWidth()/2, image.getHeight()+10, Graphics.HCENTER|Graphics.TOP);
			addCommand(continueCommand);
		}
	}
	
	protected void keyPressed(int keyCode) {
		int action = getGameAction(keyCode);
		int xOf33 = -1, yOf33 = -1;
		for (int x = 0; x < 4; x ++) {
			for (int y = 0; y < 4; y ++) {
				if (map[x][y] == 33) {
					xOf33 = x;
					yOf33 = y;
					xmap33 = x;
					ymap33 = y;
					break;
				}
			}
		}
		switch(action) {
			case GameCanvas.UP:
				if (yOf33 != 3) {
					//graphics.setColor(255, 0, 0);
					//graphics.drawRect(xOf33*edge+2, (yOf33+1)*edge+2, edge-4, edge-4);
					willSwapX = 0;
					willSwapY = 1;
				}
				break;
			case GameCanvas.DOWN:
				if (yOf33 != 0) {
					willSwapX = 0;
					willSwapY = -1;
				}
				break;
			case GameCanvas.LEFT:
				if (xOf33 != 3) {
					willSwapX = 1;
					willSwapY = 0;
				}
				break;
			case GameCanvas.RIGHT:
				if (xOf33 != 0) {
					willSwapX = -1;
					willSwapY = 0;
				}
				break;
		}
		repaint();
	}
	
	protected void keyRepeated(int keyCode) {
		int action = getGameAction(keyCode);
		if (action == GameCanvas.FIRE) {
			willShowFullImage = true;
		}
		repaint();
	}
	
	protected void keyReleased(int keyCode) {
		willShowFullImage = false;
		int action = getGameAction(keyCode);
		/*int xOf33 = -1, yOf33 = -1;
		for (int x = 0; x < 4; x ++) {
			for (int y = 0; y < 4; y ++) {
				if (map[x][y] == 33) {
					xOf33 = x;
					yOf33 = y;
					break;
				}
			}
		}*/
		int xOf33 = xmap33, yOf33 = ymap33;
		switch(action) {
			case GameCanvas.UP:
				if (yOf33 != 3) {
					swap(xOf33, yOf33, xOf33, yOf33 + 1);
				}
				break;
			case GameCanvas.DOWN:
				if (yOf33 != 0) {
					swap(xOf33, yOf33, xOf33, yOf33 - 1);
				}
				break;
			case GameCanvas.LEFT:
				if (xOf33 != 3) {
					swap(xOf33, yOf33, xOf33 + 1, yOf33);
				}
				break;
			case GameCanvas.RIGHT:
				if (xOf33 != 0) {
					swap(xOf33, yOf33, xOf33 - 1, yOf33);
				}
				break;
		}
		willSwapX = 0;
		willSwapY = 0;
		repaint();
	}
	
	public void commandAction(Command c, Displayable d) {
		if (c == exitCommand) {
			/*try {
				midlet.destroyApp(true);
			} catch(Exception ex) {
				
			}*/
			midlet.notifyDestroyed();
		}
		else if (c == continueCommand) {
			removeCommand(continueCommand);
			initMap();
		}
	}
}
